Skip to content

Comments

feature(webapp): Show a v3 deprecation notice in the side bar#3090

Merged
samejr merged 4 commits intomainfrom
feature(webapp)-add-v3-notification
Feb 19, 2026
Merged

feature(webapp): Show a v3 deprecation notice in the side bar#3090
samejr merged 4 commits intomainfrom
feature(webapp)-add-v3-notification

Conversation

@samejr
Copy link
Member

@samejr samejr commented Feb 19, 2026

  • If your project is v3, show a v3 deprecation panel in the side menu
  • If there is an active incident, show the incident panel instead
  • Links to the Migration guide in the docs
  • Displays when the side menu is collapsed
CleanShot.2026-02-19.at.08.17.32.mp4
CleanShot 2026-02-19 at 08 13 59@2x

@changeset-bot
Copy link

changeset-bot bot commented Feb 19, 2026

⚠️ No Changeset found

Latest commit: 462bce6

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 19, 2026

Walkthrough

SideMenu now imports additional heroicons and useIncidentStatus, derives isV3Project from project.engine, and passes explicit props (title, hasIncident, isManagedCloud, isCollapsed) into IncidentStatusPanel rather than letting it derive status internally. For V3 projects without incidents, a new collapsible V3DeprecationPanel with V3DeprecationContent is rendered beneath the incident panel; it includes an ExclamationTriangleIcon trigger, tooltip, animated collapse behavior, and a migration CTA link. IncidentStatusPanel’s prop signature was changed to accept the full props object.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is largely incomplete. It omits required sections including the issue link (Closes #), the checklist, and Testing section, though it includes key implementation details and screenshots. Add the issue number with 'Closes #', complete the checklist items, and include a Testing section describing how the changes were tested.
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding a v3 deprecation notice to the side bar, which aligns with the primary modification across both affected files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature(webapp)-add-v3-notification

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
apps/webapp/app/components/navigation/SideMenu.tsx (3)

48-49: Nit: Group heroicon imports together.

ExclamationTriangleIcon from @heroicons/react/24/outline is separated from the other @heroicons/react/20/solid imports at lines 1–24. Moving it adjacent to those keeps the import block scannable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/components/navigation/SideMenu.tsx` around lines 48 - 49, The
ExclamationTriangleIcon import is separated from the other heroicons; move the
import of ExclamationTriangleIcon so it sits next to the other `@heroicons/react`
imports (the existing 20/solid imports) to keep the import block grouped and
scannable—update the import statements at the top of SideMenu.tsx so all
heroicon symbols (including ExclamationTriangleIcon) are adjacent.

628-633: Eliminate duplicate useIncidentStatus polling.

Both IncidentStatusPanel (line 602) and V3DeprecationPanel (line 629) independently call useIncidentStatus(), creating two separate 60-second polling intervals. Lift the hook call to the SideMenu parent component and pass hasIncident as a prop to both consumers to avoid the redundant network requests.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/components/navigation/SideMenu.tsx` around lines 628 - 633,
Move the useIncidentStatus() call out of the child components and into the
SideMenu component so polling runs once: remove the useIncidentStatus() calls
from V3DeprecationPanel and IncidentStatusPanel, add a single const {
hasIncident } = useIncidentStatus() in SideMenu, and pass hasIncident down as a
prop to both V3DeprecationPanel and IncidentStatusPanel (update their param
types to accept hasIncident: boolean) so they use the passed value instead of
invoking useIncidentStatus() themselves.

603-603: Add clarity to the engine version mapping with a named constant or inline comment.

The isV3={project.engine === "V1"} mapping is correct—engine "V1" represents v3 projects and "V2" represents v4 projects—but the engine/product version mismatch can be confusing. Consider extracting a helper constant like const isV3Project = project.engine === "V1" near the top of the component or adding a brief inline comment to self-document this relationship.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/components/navigation/SideMenu.tsx` at line 603, The V3
deprecation prop is confusing because it passes isV3={project.engine === "V1"};
extract a clearly named boolean (e.g., const isV3Project = project.engine ===
"V1") near the top of the SideMenu component and use isV3={isV3Project} when
rendering V3DeprecationPanel (or, if you prefer not to add a variable, add a
one-line inline comment next to the prop explaining that engine "V1" maps to v3
projects) to make the engine-to-product-version mapping explicit and
self-documenting.
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ec7722 and 68d686d.

📒 Files selected for processing (1)
  • apps/webapp/app/components/navigation/SideMenu.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
🧠 Learnings (2)
📚 Learning: 2026-02-03T18:27:49.039Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2994
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx:553-555
Timestamp: 2026-02-03T18:27:49.039Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx, the menu buttons (like the Edit button with PencilSquareIcon) intentionally have no text labels - only icons are shown in the TableCellMenu. This is a deliberate UI design pattern for compact icon-only menu items.

Applied to files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
📚 Learning: 2026-02-11T16:37:32.429Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3019
File: apps/webapp/app/components/primitives/charts/Card.tsx:26-30
Timestamp: 2026-02-11T16:37:32.429Z
Learning: In projects using react-grid-layout, avoid relying on drag-handle class to imply draggability. Ensure drag-handle elements only affect dragging when the parent grid item is configured draggable in the layout; conditionally apply cursor styles based on the draggable prop. This improves correctness and accessibility.

Applied to files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
🧬 Code graph analysis (1)
apps/webapp/app/components/navigation/SideMenu.tsx (1)
apps/webapp/app/routes/resources.incidents.tsx (1)
  • useIncidentStatus (41-71)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (25)
  • GitHub Check: sdk-compat / Deno Runtime
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: sdk-compat / Node.js 20.20 (ubuntu-latest)
  • GitHub Check: sdk-compat / Bun Runtime
  • GitHub Check: sdk-compat / Node.js 22.12 (ubuntu-latest)
  • GitHub Check: sdk-compat / Cloudflare Workers
  • GitHub Check: typecheck / typecheck
🔇 Additional comments (3)
apps/webapp/app/components/navigation/SideMenu.tsx (3)

635-677: Clean collapse/expand implementation.

The dual motion.div approach with inverse height/opacity animations is a good pattern and stays consistent with the rest of the side menu's collapsible behavior. The popover for collapsed state provides a nice UX for showing the full deprecation content when the sidebar is narrow.


680-704: Deprecation content looks good.

Clear messaging, appropriate visual treatment with amber theming, and a well-placed CTA. Implementation is clean.


693-701: No action required. The migration docs URL is correct and properly configured.

The URL https://trigger.dev/docs/migrating-from-v3 is verified against the codebase documentation configuration:

  • The docs file docs/migrating-from-v3.mdx exists
  • docs/docs.json confirms the route slug "migrating-from-v3" with redirect mapping
  • The URL pattern is consistent with other documentation links across the codebase
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/webapp/app/components/navigation/SideMenu.tsx`:
- Around line 48-49: The ExclamationTriangleIcon import is separated from the
other heroicons; move the import of ExclamationTriangleIcon so it sits next to
the other `@heroicons/react` imports (the existing 20/solid imports) to keep the
import block grouped and scannable—update the import statements at the top of
SideMenu.tsx so all heroicon symbols (including ExclamationTriangleIcon) are
adjacent.
- Around line 628-633: Move the useIncidentStatus() call out of the child
components and into the SideMenu component so polling runs once: remove the
useIncidentStatus() calls from V3DeprecationPanel and IncidentStatusPanel, add a
single const { hasIncident } = useIncidentStatus() in SideMenu, and pass
hasIncident down as a prop to both V3DeprecationPanel and IncidentStatusPanel
(update their param types to accept hasIncident: boolean) so they use the passed
value instead of invoking useIncidentStatus() themselves.
- Line 603: The V3 deprecation prop is confusing because it passes
isV3={project.engine === "V1"}; extract a clearly named boolean (e.g., const
isV3Project = project.engine === "V1") near the top of the SideMenu component
and use isV3={isV3Project} when rendering V3DeprecationPanel (or, if you prefer
not to add a variable, add a one-line inline comment next to the prop explaining
that engine "V1" maps to v3 projects) to make the engine-to-product-version
mapping explicit and self-documenting.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
apps/webapp/app/components/navigation/SideMenu.tsx (2)

706-709: Extract hardcoded deprecation dates as named constants.

"1 April 2026" and "1 July 2026" are buried in a JSX string. If the timeline shifts, these require a string-search to find. Named constants at module scope make them easy to locate and update in one place.

♻️ Proposed refactor
+const V3_DEPLOY_STOP_DATE = "1 April 2026";
+const V3_SHUTDOWN_DATE = "1 July 2026";

 function V3DeprecationContent() {
   return (
     <div className="flex flex-col gap-2 rounded border border-amber-500/30 bg-amber-500/10 p-2 pt-1.5">
       ...
       <Paragraph variant="extra-small/bright" className="text-amber-300">
-        This is a v3 project. V3 deploys will stop working on 1 April 2026. Full shutdown is 1 July
-        2026 where all v3 runs will stop executing. Migrate to v4 to avoid downtime.
+        This is a v3 project. V3 deploys will stop working on {V3_DEPLOY_STOP_DATE}. Full shutdown
+        is {V3_SHUTDOWN_DATE} where all v3 runs will stop executing. Migrate to v4 to avoid downtime.
       </Paragraph>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/components/navigation/SideMenu.tsx` around lines 706 - 709,
Extract the hardcoded dates in SideMenu.tsx into module-level named constants
(e.g., V3_DEPLOY_STOP_DATE and V3_FULL_SHUTDOWN_DATE) and replace the inline
strings in the Paragraph JSX (the element using variant="extra-small/bright")
with those constants so future timeline updates only require changing the
constants at the top of the file.

639-695: Consider extracting a shared CollapsibleSidePanel primitive to eliminate structural duplication.

V3DeprecationPanel is structurally identical to IncidentStatusPanel: both wrap content in a Popover, animate between a full view and a collapsed icon trigger via two motion.divs, and use the same SimpleTooltip/PopoverTrigger icon pattern. If a third panel is ever added, this triplicate boilerplate will be error-prone to maintain.

A thin shared primitive (accepting isCollapsed, collapsedIcon, tooltipContent, and a children render slot) would eliminate the duplication.

Also a minor nit: Line 690 has className="w-52 !min-w-0 p-0" while the equivalent in IncidentStatusPanel (line 128 of resources.incidents.tsx) is "!min-w-0 w-52 p-0" — inconsistent ordering.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/components/navigation/SideMenu.tsx` around lines 639 - 695,
V3DeprecationPanel duplicates the same Popover + two motion.div collapse/expand
pattern used by IncidentStatusPanel; extract a CollapsibleSidePanel primitive
that accepts props {isCollapsed, collapsedIcon, tooltipContent, children} (or
similar) to render the Popover, the two motion.div states, the
SimpleTooltip/PopoverTrigger icon, and the PopoverContent slot; then refactor
V3DeprecationPanel and IncidentStatusPanel to render CollapsibleSidePanel with
their specific collapsedIcon (ExclamationTriangleIcon), tooltipContent ("V3
deprecation warning"), and children (V3DeprecationContent or incident content);
also normalize the PopoverContent className ordering (use consistent "!min-w-0
w-52 p-0") to match IncidentStatusPanel.
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 68d686d and e47ad43.

📒 Files selected for processing (2)
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/routes/resources.incidents.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/routes/resources.incidents.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/routes/resources.incidents.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/routes/resources.incidents.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/routes/resources.incidents.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/routes/resources.incidents.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/routes/resources.incidents.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
🧠 Learnings (2)
📚 Learning: 2026-02-03T18:27:40.429Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2994
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx:553-555
Timestamp: 2026-02-03T18:27:40.429Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx, the menu buttons (e.g., Edit with PencilSquareIcon) in the TableCellMenu are intentionally icon-only with no text labels as a compact UI pattern. This is a deliberate design choice for this route; preserve the icon-only behavior for consistency in this file.

Applied to files:

  • apps/webapp/app/routes/resources.incidents.tsx
📚 Learning: 2026-02-11T16:37:32.429Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3019
File: apps/webapp/app/components/primitives/charts/Card.tsx:26-30
Timestamp: 2026-02-11T16:37:32.429Z
Learning: In projects using react-grid-layout, avoid relying on drag-handle class to imply draggability. Ensure drag-handle elements only affect dragging when the parent grid item is configured draggable in the layout; conditionally apply cursor styles based on the draggable prop. This improves correctness and accessibility.

Applied to files:

  • apps/webapp/app/routes/resources.incidents.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
🧬 Code graph analysis (1)
apps/webapp/app/components/navigation/SideMenu.tsx (1)
apps/webapp/app/routes/resources.incidents.tsx (2)
  • useIncidentStatus (41-71)
  • IncidentStatusPanel (73-133)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (25)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: sdk-compat / Node.js 20.20 (ubuntu-latest)
  • GitHub Check: sdk-compat / Cloudflare Workers
  • GitHub Check: sdk-compat / Node.js 22.12 (ubuntu-latest)
  • GitHub Check: sdk-compat / Deno Runtime
🔇 Additional comments (3)
apps/webapp/app/routes/resources.incidents.tsx (1)

73-83: LGTM — clean prop-lifting refactor.

The signature change correctly externalizes data sourcing to the parent (SideMenu), enabling V3DeprecationPanel in SideMenu to share the same incidentStatus object without a second fetch. The prop types match the useIncidentStatus() return shape exactly.

apps/webapp/app/components/navigation/SideMenu.tsx (2)

604-614: LGTM — prop threading and panel ordering are correct.

IncidentStatusPanel correctly receives all three props from incidentStatus. V3DeprecationPanel is correctly gated by hasIncident to yield to the incident panel when active. The mutual-exclusion logic (!isV3 || hasIncident in the deprecation panel) matches the PR spec.


169-169: The engine mapping is correct; consider adding an inline comment for clarity.

The variable isV3Project is correctly set when engine === "V1" because V1 is the legacy engine for v3 SDK projects and V2 is the new managed engine for v4 SDK projects. This is confirmed by the upgrade paths throughout the codebase (createDeploymentBackgroundWorkerV3.server.ts, initializeDeployment.server.ts, etc.) which all upgrade projects from V1 to V2, and by DevPresence at line 345 which checks engine === "V2" for v4-specific features.

The logic is sound but the naming is counter-intuitive—an inline comment explaining the mapping (e.g., // V1 = v3 SDK engine) would improve maintainability for future developers.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/webapp/app/components/navigation/SideMenu.tsx`:
- Around line 706-709: Extract the hardcoded dates in SideMenu.tsx into
module-level named constants (e.g., V3_DEPLOY_STOP_DATE and
V3_FULL_SHUTDOWN_DATE) and replace the inline strings in the Paragraph JSX (the
element using variant="extra-small/bright") with those constants so future
timeline updates only require changing the constants at the top of the file.
- Around line 639-695: V3DeprecationPanel duplicates the same Popover + two
motion.div collapse/expand pattern used by IncidentStatusPanel; extract a
CollapsibleSidePanel primitive that accepts props {isCollapsed, collapsedIcon,
tooltipContent, children} (or similar) to render the Popover, the two motion.div
states, the SimpleTooltip/PopoverTrigger icon, and the PopoverContent slot; then
refactor V3DeprecationPanel and IncidentStatusPanel to render
CollapsibleSidePanel with their specific collapsedIcon
(ExclamationTriangleIcon), tooltipContent ("V3 deprecation warning"), and
children (V3DeprecationContent or incident content); also normalize the
PopoverContent className ordering (use consistent "!min-w-0 w-52 p-0") to match
IncidentStatusPanel.

@samejr samejr marked this pull request as ready for review February 19, 2026 08:53
Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

Copy link
Member

@ericallam ericallam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That "Migrate to v4 now" button makes it seem like clicking that button will migrate your project, which will lead to people not click on it because they'll be worried it will be a destructive action. Make it clear its a docs link I think

@samejr
Copy link
Member Author

samejr commented Feb 19, 2026

Good call @ericallam - i've changed it to this:

CleanShot 2026-02-19 at 10 44 50@2x

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/webapp/app/components/navigation/SideMenu.tsx (1)

653-695: Hidden PopoverTrigger remains focusable when the sidebar is expanded.

When isCollapsed is false, the collapsed-state motion.div (lines 668-689) animates to height: 0 / opacity: 0 but the PopoverTrigger inside it stays in the DOM and is keyboard-focusable. A user tabbing through the sidebar could activate the popover and see the deprecation content duplicated in a popover alongside the inline panel.

Consider conditionally rendering the collapsed block, or applying aria-hidden and tabIndex={-1} when not collapsed:

Suggested approach
         <motion.div
           initial={false}
           animate={{
             height: isCollapsed ? "auto" : 0,
             opacity: isCollapsed ? 1 : 0,
           }}
           transition={{ duration: 0.15 }}
-          className="overflow-hidden"
+          className="overflow-hidden"
+          aria-hidden={!isCollapsed}
+          {...(!isCollapsed && { inert: "" })}
         >

Alternatively, gate the entire collapsed block with {isCollapsed && (...)} and remove the animation for that direction.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/components/navigation/SideMenu.tsx` around lines 653 - 695,
The collapsed-state panel containing PopoverTrigger stays in the DOM and remains
keyboard-focusable when isCollapsed is false; update the component so the
collapsed block (the motion.div wrapping SimpleTooltip/PopoverTrigger) either is
only rendered when isCollapsed (e.g., gate it with {isCollapsed && (...)} to
remove the element entirely) or, if you keep animation, set accessibility
attributes on the focusable element(s): add aria-hidden="true" and tabIndex={-1}
to the PopoverTrigger (and any focusable children) when isCollapsed is false to
prevent keyboard focus and duplicate popover activation; reference the
motion.div, isCollapsed, PopoverTrigger and SimpleTooltip when making the
change.
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e47ad43 and 3799da3.

📒 Files selected for processing (1)
  • apps/webapp/app/components/navigation/SideMenu.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
🧠 Learnings (1)
📚 Learning: 2026-02-11T16:37:32.429Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3019
File: apps/webapp/app/components/primitives/charts/Card.tsx:26-30
Timestamp: 2026-02-11T16:37:32.429Z
Learning: In projects using react-grid-layout, avoid relying on drag-handle class to imply draggability. Ensure drag-handle elements only affect dragging when the parent grid item is configured draggable in the layout; conditionally apply cursor styles based on the draggable prop. This improves correctness and accessibility.

Applied to files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (27)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: sdk-compat / Cloudflare Workers
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: sdk-compat / Node.js 22.12 (ubuntu-latest)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: sdk-compat / Node.js 20.20 (ubuntu-latest)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: sdk-compat / Deno Runtime
  • GitHub Check: typecheck / typecheck
  • GitHub Check: sdk-compat / Bun Runtime
🔇 Additional comments (3)
apps/webapp/app/components/navigation/SideMenu.tsx (3)

604-615: LGTM!

Clean separation of concerns: IncidentStatusPanel now receives explicit props instead of deriving state internally, and the V3DeprecationPanel is correctly placed below it with proper conditional logic (isV3 and hasIncident).


698-724: LGTM!

Clear, well-structured deprecation content with appropriate urgency messaging and a direct link to the migration guide. The amber color scheme effectively communicates warning severity.


170-170: No action needed. Line 170 is correct: project.engine === "V1" correctly identifies v3 projects. The engine version scheme (V1 = v3 product, V2 = v4 product) is intentionally inverted from the product versioning, as confirmed by codebase patterns like run.engine === "V1" being used to route to #getV3TaskRunContext.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/webapp/app/components/navigation/SideMenu.tsx`:
- Around line 653-695: The collapsed-state panel containing PopoverTrigger stays
in the DOM and remains keyboard-focusable when isCollapsed is false; update the
component so the collapsed block (the motion.div wrapping
SimpleTooltip/PopoverTrigger) either is only rendered when isCollapsed (e.g.,
gate it with {isCollapsed && (...)} to remove the element entirely) or, if you
keep animation, set accessibility attributes on the focusable element(s): add
aria-hidden="true" and tabIndex={-1} to the PopoverTrigger (and any focusable
children) when isCollapsed is false to prevent keyboard focus and duplicate
popover activation; reference the motion.div, isCollapsed, PopoverTrigger and
SimpleTooltip when making the change.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/webapp/app/components/navigation/SideMenu.tsx (1)

711-712: Consider extracting hardcoded deprecation dates to named constants

The dates "1 April 2026" and "1 July 2026" are embedded directly in UI copy. If dates slip or the message needs updating, it requires a text search through JSX. Extracting them makes future changes less error-prone.

♻️ Proposed refactor
+const V3_DEPLOY_DEADLINE = "1 April 2026";
+const V3_SHUTDOWN_DEADLINE = "1 July 2026";

 function V3DeprecationContent() {
   return (
     ...
       <Paragraph variant="extra-small/bright" className="text-amber-300">
-        This is a v3 project. V3 deploys will stop working on 1 April 2026. Full shutdown is 1 July
-        2026 where all v3 runs will stop executing. Migrate to v4 to avoid downtime.
+        This is a v3 project. V3 deploys will stop working on {V3_DEPLOY_DEADLINE}. Full shutdown
+        is {V3_SHUTDOWN_DEADLINE} where all v3 runs will stop executing. Migrate to v4 to avoid
+        downtime.
       </Paragraph>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/components/navigation/SideMenu.tsx` around lines 711 - 712,
The hardcoded dates in the SideMenu JSX ("1 April 2026" and "1 July 2026")
should be extracted to named constants so future updates are easier; declare
constants like V3_DEPRECATION_DATE and V3_FULL_SHUTDOWN_DATE (either at the top
of the SideMenu.tsx module or in a shared constants file) and replace the
literal strings in the component's render/JSX with those constants (e.g., use
{V3_DEPRECATION_DATE} and {V3_FULL_SHUTDOWN_DATE} inside the message) ensuring
any tests or i18n handling are updated accordingly.
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3799da3 and 462bce6.

📒 Files selected for processing (1)
  • apps/webapp/app/components/navigation/SideMenu.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
🧠 Learnings (1)
📚 Learning: 2026-02-11T16:37:32.429Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3019
File: apps/webapp/app/components/primitives/charts/Card.tsx:26-30
Timestamp: 2026-02-11T16:37:32.429Z
Learning: In projects using react-grid-layout, avoid relying on drag-handle class to imply draggability. Ensure drag-handle elements only affect dragging when the parent grid item is configured draggable in the layout; conditionally apply cursor styles based on the draggable prop. This improves correctness and accessibility.

Applied to files:

  • apps/webapp/app/components/navigation/SideMenu.tsx
🧬 Code graph analysis (1)
apps/webapp/app/components/navigation/SideMenu.tsx (1)
apps/webapp/app/routes/resources.incidents.tsx (2)
  • useIncidentStatus (41-71)
  • IncidentStatusPanel (73-133)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (27)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: sdk-compat / Node.js 22.12 (ubuntu-latest)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: sdk-compat / Deno Runtime
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: sdk-compat / Bun Runtime
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: sdk-compat / Node.js 20.20 (ubuntu-latest)
  • GitHub Check: sdk-compat / Cloudflare Workers
🔇 Additional comments (1)
apps/webapp/app/components/navigation/SideMenu.tsx (1)

714-724: No action required — LinkButton automatically handles rel="noopener noreferrer"

The LinkButton component delegates external URLs (starting with "http") to the ExtLink component, which hardcodes both target="_blank" and rel="noopener noreferrer" on the underlying <a> element. The migration guide link is already secure and follows best practices.

Likely an incorrect or invalid review comment.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/webapp/app/components/navigation/SideMenu.tsx`:
- Around line 711-712: The hardcoded dates in the SideMenu JSX ("1 April 2026"
and "1 July 2026") should be extracted to named constants so future updates are
easier; declare constants like V3_DEPRECATION_DATE and V3_FULL_SHUTDOWN_DATE
(either at the top of the SideMenu.tsx module or in a shared constants file) and
replace the literal strings in the component's render/JSX with those constants
(e.g., use {V3_DEPRECATION_DATE} and {V3_FULL_SHUTDOWN_DATE} inside the message)
ensuring any tests or i18n handling are updated accordingly.

@samejr samejr merged commit 506b161 into main Feb 19, 2026
42 checks passed
@samejr samejr deleted the feature(webapp)-add-v3-notification branch February 19, 2026 11:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants